package sii.challenge.gestoreratings;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import sii.challenge.main.DataSource;
import sii.challenge.modello.Rating;
import sii.challenge.modello.SimilaritaUtenti;
import sii.challenge.modello.Utente;

/** Classe per la gestione della similarita' fra utenti.
 * 
 * @author dario, francesco
 *
 */
public class GestoreSimilaritaUtenti {
	protected DataSource dataSource;
	protected Connection connection;


	/** Numero degli utenti simili da trovare. */
	public final int NUMERO_UTENTI = 500;

	/** Mappa per le similarita gia' calcolate. */
//	private Map<Integer, Integer> mappa_similarita_fatte;

	/** Costruttore. */
	public GestoreSimilaritaUtenti() {

//		mappa_similarita_fatte= new HashMap<Integer, Integer>();
	}

	/** Trova gli utenti piu simili. */
	public List<SimilaritaUtenti> utentiSimili(Utente utente_a, Map<Integer, Utente> mappa_utenti) {

		// variabili di supporto per memorizzare le similarita.
		List<SimilaritaUtenti> all_utenti_simili = new ArrayList<SimilaritaUtenti>();
		List<SimilaritaUtenti> most_utenti_simili = new ArrayList<SimilaritaUtenti>();
		



		// per tutti gli utenti_b si cerca la sim(a,b). 
		for (Utente utente_b: mappa_utenti.values()) {
			if(utente_a.getId()!=utente_b.getId()){
//				if(!mappa_similarita_fatte.containsKey(utente_b.getId())){
//					mappa_similarita_fatte.put(utente_a.getId(), 0);

					SimilaritaUtenti sim;
					if((sim=sim(utente_a, utente_b)).getSimilarita()>=0.80)
						all_utenti_simili.add(sim);
			}

//				}
		}
		if(all_utenti_simili.size()>NUMERO_UTENTI){
			for (int i=0; i<NUMERO_UTENTI; i++){
				// massimo provvisorio = il primo della lista.
				SimilaritaUtenti max_temp = all_utenti_simili.get(0);
				for (SimilaritaUtenti sim : all_utenti_simili) {
					if (sim.getSimilarita() > max_temp.getSimilarita())
						max_temp = sim;
				}
				most_utenti_simili.add(max_temp);
				all_utenti_simili.remove(max_temp);
			}
			return most_utenti_simili;
		}



		return all_utenti_simili;
	}


	/** Calcola la similarita fra due utenti in base ai voti che danno alle stesse persone */
	public SimilaritaUtenti sim(Utente utente_a, Utente utente_b) {

		// variabili di supporto per il calcolo della Pearson Correlation. 
		double somma_numeratore = 0;
		double somma_denominatore1 = 0;
		double somma_denominatore2 = 0;
		double similarita = 0;

		// se non ho informazioni riguardo i due utenti, salta il calcolo della similarita'.
		if(utente_a != null && utente_b != null) {
			double r_avg_a = utente_a.getAvgRating();
			double r_avg_b = utente_b.getAvgRating();

			// per tutti i rating dell'utente b. 
			for (Rating rating_b : utente_b.getMappaRating().values()) {
				int idProfile = rating_b.getIdProfile();

				if(utente_a.getMappaRating().get(idProfile) != null) {
					Rating rating_a = utente_a.getMappaRating().get(idProfile);
					double temp1 = rating_a.getRatingValue() - r_avg_a;
					double temp2 = rating_b.getRatingValue() - r_avg_b;
					somma_numeratore = somma_numeratore + (temp1*temp2);
					somma_denominatore1 = somma_denominatore1 + (temp1*temp1);
					somma_denominatore2 = somma_denominatore2 + (temp2*temp2);

				}
			}

		}
		// calcola la pearson correlation e crea un nuovo oggetto Similarita.
		double denominatore = (Math.sqrt(somma_denominatore1))*(Math.sqrt(somma_denominatore2));
		

		if (denominatore != 0) {
			similarita = (somma_numeratore/denominatore);
		}
		SimilaritaUtenti sim = new SimilaritaUtenti(utente_a, utente_b, similarita);

		return sim;
	}
}
